package pl.klangner.recobox.classifier
{
	import pl.klangner.recobox.geometry.Vector;
	

	/**
	 */
	public class DirectionClassifier 
	{
		// --------------------------------------------------------------------------------------------
		public function DirectionClassifier(){
			
			initPatterns();
		}
		
		// --------------------------------------------------------------------------------------------
		public function get gestures():String{
			return _gestures;
		}
		
		// --------------------------------------------------------------------------------------------
		/**
		 * 
		 * @return Stroke with recognized type
		 */
		public function classify(input:InkMultiStroke):String{	
			
			_gestures = extractDirections(input.simplifiedPoints);
			
			return findCharacter(_gestures);
		}
		
		// --------------------------------------------------------------------------------------------
		/**
		 * Train recognizer on given samples
		 */
		public function train(samples:Object):void{
			
			_patterns = new Array();
			for( var key:String in samples ){
				for each( var ref:String in samples[key] ){
	  			var stroke:InkMultiStroke = new InkMultiStroke();
	  			var pattern:DirectionPattern;
	  			var dir:String; 
	  			
	  			stroke.loadFromString(ref);
	  			dir = extractDirections(stroke.simplifiedPoints);
	  			trace( key + " -> " + dir );
	  			pattern = new DirectionPattern( key, dir );
	  			_patterns.push( pattern );
	  		}
			}
		}
		
		// --------------------------------------------------------------------------------------------
		/**
		 * Decodes input stroke as series of directions based on vectors.
		 * Directions and the codes:
		 *                G
		 *              F   H
		 *            E       A
		 *              D   B
		 *                C
		 */ 
		private function extractDirections(points:Array):String{
			
			var directions:String = "";
			var A:String = "A";
			var i:int;
			var lastDir:int = -1;
			
			for(i = 0; i < points.length-1; i++){
			
				var v:Vector = Vector.points2Vector(points[i], points[i+1]);
				var angle:Number = v.angle + 1/8*Math.PI;	
				var dir:int = Math.floor( angle/(1/4*Math.PI) );

				if(dir == 8)
					dir = 0;
					
				if(dir != lastDir)
					directions += String.fromCharCode( A.charCodeAt(0)+dir );
					
				lastDir = dir;
			}
			
			return directions;
		}
		
		// --------------------------------------------------------------------------------------------
		/**
		 * Look for character which matches given gestures
		 */
		private function findCharacter(gestures:String):String{
			
			for each(var pattern:DirectionPattern in _patterns){
				if( pattern.compare(gestures) )
					return pattern.name;
			}
			
			return null;
		}
		
		
		// --------------------------------------------------------------------------------------------
		/**
		 * Read patters from internal database
		 */
		private function initPatterns():void{
			
			_patterns = new Array();
			for( var key:String in PATTERN_DATA ){
				for each( var item:String in PATTERN_DATA[key] ){
	  			var pattern:DirectionPattern;
	  			
	  			pattern = new DirectionPattern( key, item );
	  			_patterns.push( pattern );
	  		}
			}
		}
		
		// --------------------------------------------------------------------------------------------
		// Private members
		private var _gestures:String;
		private var _patterns:Array;
		
		private static var PATTERN_DATA:Object = {
			"0":["EDCBHF", "ECBAHF", "DBHF", "DBGF", "DCBAGF", "ECBAHFE"],
			"1":["HC"],
			"2":["ADA", "ABDA", "ACDA", "ABCDA", "HBDA", "HACDA", "HCDA", "HABDA", "HBCDA"],
			"3":["ADACE", "HADBE", "HBDACDF", "ACDADE", "ADBDE", "ABDBE", "ADBCE", "ABDAE", "ACEBDE"],
			"4":["EHC", "CAGC", "CAHC"],
			"5":["ECABDE", "ECABCE", "ECHBD", "ECACDF"],
			"6":["EDBAGE", "EDCBGE", "DCAHF", "EDCAGE"],
			"7":["AD", "AC"],
			"8":["ECBACDFHF", "EDBDEH", "ECBDEGHE", "DBCEFHF", "DBDFHF"],
			"9":["EDBHCE", "EBAHCE", "EBHGCE", "DBHGCE", "EDAGCE"]
		};
	}
}